package com.csaba.connector.citi;

import java.io.StringReader;
import java.util.logging.Logger;

import org.apache.commons.httpclient.NameValuePair;

import com.csaba.connector.ServiceException;
import com.csaba.connector.citi.model.CitiBank;
import com.csaba.connector.citi.model.CitiRequestFactory;
import com.csaba.connector.citi.model.CitiSession;
import com.csaba.connector.citi.parser.CitiCodes;
import com.csaba.connector.citi.parser.CitiParser;
import com.csaba.connector.citi.parser.LoginParser;
import com.csaba.connector.model.Session;
import com.csaba.connector.service.AbstractLoginService;
import com.csaba.util.LoggerHelper;

public class CitiLoginService extends AbstractLoginService
{
	private final static Logger logger = LoggerHelper.getDefaultLogger();

	@Override
	public void execute( final Session session ) throws ServiceException
	{
		final String userId = customer.getLoginId();
		final String password = customer.getPassword();

		if ( userId.length() < 6 )
			throw new ServiceException("User Name should be minimum of 6 characters.");
		if ( password.length() < 6 )
			throw new ServiceException("Password should be minimum of 6 characters.");

		if ( customer == null )
			throw new ServiceException("Login service is not correctly initialized.");
		if ( session != null )
			throw new ServiceException("Session is already initialized. Cannot login again in the same session.");

		this.session = new CitiSession();
		final CitiSession citiSession = (CitiSession) this.session;

		//Obtain login screen + sessionID in cookie
		final String resultRequestSessionID = citiSession.doGetWithTimeStamp(CitiRequestFactory.HOMEBANK_URL_BASE
				+ CitiRequestFactory.REQUEST_SESSION_ID_TS_NEEDED);
		citiSession.debugFile("resultRequestSessionID", resultRequestSessionID);

		if ( citiSession.isSessionIDAvailable() )
		{
			logger.fine("Login screen and sessionID is obtained.");
		}
		else
		{
			final String message = "SessionID is not available.";
			throw new ServiceException("Error occured during logging in.", message);
		}

		//login
		final NameValuePair[] loginData = new NameValuePair[] { new NameValuePair(CitiCodes.USER_ID, userId),
				new NameValuePair(CitiCodes.PASSWORD, password), new NameValuePair("serviceFlag", "signon") };
		final String resultRequestLogin = citiSession.doPost(CitiRequestFactory.HOMEBANK_URL_BASE
				+ CitiRequestFactory.REQUEST_LOGIN, loginData);
		citiSession.debugFile("resultRequestLogin", resultRequestLogin);

		try
		{
			final String nextURL = LoginParser.parseNextURL(new StringReader(resultRequestLogin));

			if ( nextURL.isEmpty() )
				throw new IllegalStateException(resultRequestLogin);
			logger.fine("Succesful login");

			final NameValuePair nameValuePair = LoginParser.parseValue(new StringReader(resultRequestLogin),
					CitiCodes.AUTHTOK_CITIDIRECT);

			//create menu structure		
			final String resultMenuStructure = citiSession.doPost(nextURL, new NameValuePair[] { nameValuePair });
			citiSession.debugFile("resultMenuStructure", resultMenuStructure);
			final String mainMenuURL = LoginParser.parseMainMenuURL(new StringReader(resultMenuStructure));

			if ( mainMenuURL.isEmpty() )
				throw new IllegalStateException(resultMenuStructure);
			logger.fine("Succesful creation of menu structure");

			//create main menu
			final String resultMainMenu = citiSession.doGet(mainMenuURL);
			citiSession.debugFile("resultMainMenu", resultMainMenu);
			// <form id="F1" action="/HomeBankingSecure/insess.asp?_D=NavChans&_C=HTML&_F=WorkArea324898599661954&_T=INPUT&_S=3&_V=F1&_TS=1225880393" onsubmit="return false" target="WorkArea324898599661954" method="post" name="F1" autocomplete="off">
			// https://home1hu.cbol.citibank.hu/HomeBankingSecure/insess.asp?_D=NavChans &_C=HTML&_F=WorkArea324898599661954&_T=INPUT&_NS=3&_V=F1&_TS =1225880393
			final String accountMenuURL = CitiParser.parseNextURL(new StringReader(resultMainMenu));

			if ( accountMenuURL.isEmpty() )
				throw new IllegalStateException(resultMainMenu);
			logger.fine("Succesful creation of main menu");

			//create account information menu
			// POSTDATA=SELCHOICE=CH1&SRC=IMAGE&S1=-
			final NameValuePair[] nameValuePairs = new NameValuePair[] { new NameValuePair("SELCHOICE", "CH1"),
					new NameValuePair("SRC", "IMAGE"), new NameValuePair("S1", "-") };

			final String resultAccountMenu = citiSession.doPost(accountMenuURL, nameValuePairs);
			citiSession.debugFile("resultAccountMenu", resultAccountMenu);

			// <form id="F1" action="/HomeBankingSecure/insess.asp?_D=NavWork&_C=HTML&_F=NavWork&_T=INPUT&_S=6&_V=F1&_TS=1225891245" onsubmit="return false" method="post" name="F1" autocomplete="off"/>
			// https://home1hu.cbol.citibank.hu/HomeBankingSecure/insess.asp?_D=NavWork&_C=HTML&_F=NavWork&_T=INPUT&_S=6&_V=F1&_TS=1225891245
			final String accountServiceURL = CitiParser.parseNextURL(new StringReader(resultAccountMenu));

			if ( accountServiceURL.isEmpty() )
				throw new IllegalStateException(resultAccountMenu);
			logger.fine("Succesful creation of account information menu");

			//store account balance request in the session for further processing.
			citiSession.setRemoteProperty(CitiCodes.CACHE_ACCOUNTSERVICE_URL, accountServiceURL);

			//fix customer properties
			customer.setId(userId);
			customer.setBank(CitiBank.getInstance());
			customer.setName("<Citi Customer - " + userId + ">");

			//fix session properties
			citiSession.setCustomer(customer);

			logger.fine("Login was successful.");
		}
		catch ( final IllegalStateException illegalStateException )
		{
			logger.fine("Error during login... Parsing messaging.");
			String message = null;
			try
			{
				message = CitiParser.parseErrorMsg(new StringReader(illegalStateException.getMessage()));
			}
			catch ( final Exception ex )
			{
				throw new ServiceException("Error during processing login result (error message).", ex);
			}

			throw new ServiceException("Error occured during logging in.", message);
		}
		catch ( final Exception ex )
		{
			throw new ServiceException("Error during processing login result (error message).", ex);
		}
	}
}
